"""
Case Type   : Miniaturization
Case Name   : 通过libpq的PQconnectdb函数连接数据库，target_session_attrs配置为读写
Create At   : 2024/11/14
Owner       : li-xin12345
Description :
    1.解压libpq压缩包，导入环境变量
    2.准备PQconnectdb函数连接数据库的脚本,修改文件的连接参数
    3.编译文件
    4.执行脚本
Expect      :
    1.成功
    2.成功
    3.成功
    4.成功
History     :
"""

import os
import unittest

from yat.test import Node
from yat.test import macro

from testcase.utils.Common import Common
from testcase.utils.ComInstall import LiteInstall, LiteUnInstall, LiteConfig
from testcase.utils.Logger import Logger
from testcase.utils.CommonSH import CommonSH

Primary_SH = CommonSH('PrimaryDbUser')


@unittest.skipIf(Primary_SH.get_node_num() < 2, '需至少两个环境，否则不执行')
class Lite(unittest.TestCase):
    def setUp(self):
        self.log = Logger()
        self.log.info(f'-----{os.path.basename(__file__)} start-----')
        self.pkg_path = os.path.dirname(macro.DB_SCRIPT_PATH)
        self.lite_pkg_dirname = 'lite_pkg'
        self.script_path = os.path.join(self.pkg_path, self.lite_pkg_dirname)
        self.com_install = LiteInstall(self.pkg_path, None, None)
        self.com_uninstall = LiteUnInstall(self.pkg_path)
        self.com_config = LiteConfig()
        self.root_nodes = (Node('PrimaryRoot'), Node('Standby1Root'))
        self.user_nodes = (Node('PrimaryDbUser'), Node('Standby1DbUser'))
        self.common = Common()
        self.user = None
        self.port = None
        self.assert_msg = f'start datanode success'
        self.file = 'lite_libpq_file'
        self.conn_db = 'db_lite_libpq'
        self.conn_user = 'u_lite_libpq'
        self.confile = os.path.join('/', 'etc', 'security', 'limits.conf')
        self.confile_bk = os.path.join('/', 'etc', 'security', 'limitsbk.conf')

    def test_libpq(self):
        text = '----prestep1:获取可用用户和端口----'
        self.log.info(text)
        self.user, self.port = self.com_install.get_user_and_port(
            *self.root_nodes)
        self.log.info(f'self.user:{self.user}, self.port:{self.port}')
        for node in self.user_nodes:
            node.ssh_user = self.user
            node.ssh_password = macro.COMMON_PASSWD

        self.data_path = os.path.join('/home', self.user, 'data')
        self.app_path = os.path.join('/home', self.user, 'app')
        self.com_install.data_path = self.data_path
        self.com_install.app_path = self.app_path

        text = '----prestep2:创建数据库用户和用户组;expect:创建成功----'
        self.log.info(text)
        self.com_install.prepare_user(self.user, *self.root_nodes)

        text = '----prestep3:获取数据库安装包、libbpq包并解压;expect:成功----'
        self.log.info(text)
        for node in self.root_nodes:
            res = self.com_install.tar_pkg(node)
            self.assertIn('install.sh', res, f'{node.ssh_host}-执行失败: {text}')

        text = '----prestep4:执行安装脚本安装集群;expect:执行成功----'
        self.log.info(text)
        res = self.com_install.install_cluster(self.port, *self.user_nodes)
        self.assertEqual(res.count(self.assert_msg), len(self.user_nodes),
                         f'执行失败: {text}')

        text = '----prestep5:查询主备状态;expect:执行成功----'
        self.log.info(text)
        cmd = f'gs_ctl query -D {self.data_path}'
        res = self.user_nodes[0].sh(cmd).result()
        self.log.info(res)
        self.assertRegex(res, r'db_state\s+:\s+Normal', f'执行失败: {text}')
        for i in range(1, len(self.user_nodes)):
            expect = f'{self.user_nodes[0].ssh_host}:\\d+-->' \
                     f'{self.user_nodes[i].ssh_host}:\\d+'
            self.log.info(f'expect:{expect}')
            self.assertRegex(res, expect, f'执行失败: {text}')

        text = '----prestep6:limits.conf文件中添加参数;expect:成功----'
        self.log.info(text)
        self.com_config.set_limit_conf(self.conn_user, *self.root_nodes)

        text = '----prestep7:创建数据库及用户，并配置白名单;expect:成功----'
        self.log.info(text)
        res = self.com_config.create_db(self.user_nodes[0], self.port,
                                        self.conn_db)
        self.assertIn('CREATE DATABASE', res, f'执行失败：{text}')
        res = self.com_config.create_user(self.user_nodes[0], self.port,
                                          self.conn_user)
        self.assertIn('CREATE ROLE', res, f'执行失败：{text}')
        self.assertIn('ALTER ROLE', res, f'执行失败：{text}')
        params = f"host {self.conn_db} {self.conn_user} " \
                 f"{self.root_nodes[0].ssh_host}/32 sha256"
        res = self.com_config.set_pg_hba('reload', self.data_path, params,
                                         *self.user_nodes)
        self.assertIn('Success to perform gs_guc', res, f'执行失败：{text}')

        text = '----step1:解压libpq压缩包，导入环境变量;expect:成功----'
        self.log.info(text)
        self.log.info('--在prestep3中已解压libpq压缩包--')
        self.common.scp_file(self.root_nodes[0],
                             f"{self.file}.c", self.script_path)
        cmd = f'ls {self.script_path}'
        res = self.root_nodes[0].sh(cmd).result()
        self.assertIn(self.file, res, '远程复制脚本至指定主机失败')

        text = '----step2:准备PQconnectdb函数连接数据库的脚本,修改文件的连接参数;' \
               'expect:成功----'
        self.log.info(text)
        conn_info = f"dbname={self.conn_db} port={self.port} " \
                    f"hostaddr={self.root_nodes[0].ssh_host}," \
                    f"{self.root_nodes[1].ssh_host} " \
                    f"target_session_attrs=read-write " \
                    f"connect_timeout=5 sslmode=allow " \
                    f"user='{self.conn_user}' password='{macro.COMMON_PASSWD}'"
        self.log.info(conn_info)

        text = '---step3:编译文件;expect:成功---'
        self.log.info(text)
        cmd = f"export " \
              f"LD_LIBRARY_PATH={os.path.join(self.script_path, 'lib')};" \
              f"gcc -c -I " \
              f"{os.path.join(self.script_path, 'include')} " \
              f"{os.path.join(self.script_path, f'{self.file}.c')} -o " \
              f"{os.path.join(self.script_path, f'{self.file}.o')};" \
              f"gcc -o {os.path.join(self.script_path, f'{self.file}')} " \
              f"{os.path.join(self.script_path, f'{self.file}.o')} " \
              f"{os.path.join(self.script_path, 'lib', 'libpq.so')} -ldl"
        self.log.info(cmd)
        res = self.user_nodes[0].sh(cmd).result()
        self.log.info(res)
        self.assertNotIn('error', res, f'执行失败：{text}')

        text = '---step4:执行脚本;expect:成功---'
        self.log.info(text)
        cmd = f'cd {self.script_path} && ./{self.file} "{conn_info}"'
        self.log.info(cmd)
        res = self.user_nodes[0].sh(cmd).result()
        self.log.info(res)
        self.assertIn('pg_is_in_recovery', res, f'执行失败：{text}')
        self.assertEqual('f', res.splitlines()[-1], f'执行失败：{text}')

    def tearDown(self):
        text = '----清理环境;expect:成功----'
        self.log.info(text)
        uninstall_res = self.com_uninstall.uninstall(*self.user_nodes)
        self.com_uninstall.clear_env(*self.root_nodes)
        self.com_config.restore_limit_conf(*self.root_nodes)
        self.com_config.clean_file(*self.root_nodes)
        self.assertIn('success', uninstall_res, f'执行失败: {text}')
        self.log.info(f'-----{os.path.basename(__file__)} end-----')